#include "INetwork.h"

#include <net/if.h>
#include <cstring>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <Utility.h>

#include "Log.h"
#include "ErrorCode.h"

INetwork::INetwork() : mprocessCreator(ProcessCreatorSingleton::instance()){
    msocketFd = socket(AF_INET, SOCK_DGRAM, 0);
}

INetwork::~INetwork() {
    close(msocketFd);
}



short INetwork::getIterfaceFlags(const std::string name, int socketfd) {
    ifreq request;
    std::memset(&request, 0, sizeof (request));
    std::strncpy(request.ifr_name, name.data(), sizeof(request.ifr_name));
    ioctl(socketfd, SIOCGIFFLAGS, &request);

    return request.ifr_flags;
    //  IFF_RUNNING
}



int INetwork::setIterfaceFlags(const std::string name, int socketfd, short flags){
    ifreq request;
    std::memset(&request, 0, sizeof (request));
    std::strncpy(request.ifr_name, name.data(), sizeof(request.ifr_name));
    request.ifr_flags = flags;
    int returnCode = ioctl(socketfd, SIOCSIFFLAGS, &request);
    if (0 > returnCode) {
        BUILD_EXCEPTION_ERROR(FirmwareError::NET_INTERFACE_CONFIGURE_ERROR, returnCode, errno, "setIterfaceFlags failed");
    }

    return returnCode;
}



int INetwork::setIterfaceAddressParameter(const std::string name, int socketfd, unsigned long requestCode, sockaddr_in& addr){

   ifreq request;
    std::strncpy(request.ifr_name, name.data(), sizeof(request.ifr_name));
    memcpy(&request.ifr_addr, &addr, sizeof (sockaddr));

    char buffer[STRING_BUFFER_SIZE];
    int returnCode = ioctl(socketfd, requestCode, &request);
    if (0 > returnCode) {
        //std::string prefix;//"%s(%s, %d, %ld, %p)%s", __FUNCTION__, name.data(), socketfd, requestCode, &addr, buildErrorMessage(returnCode, errno, prefix).data());
        BUILD_EXCEPTION_ERROR(FirmwareError::NET_INTERFACE_CONFIGURE_ERROR, returnCode, errno, "setIterfaceAddressParameter failed");
    }

    return returnCode;
}



void INetwork::retrieveInterfaceInfo() {
    ifreq request;
    std::strncpy(request.ifr_name, mname.data(), sizeof(request.ifr_name));

    char buffer[STRING_BUFFER_SIZE];
    int returnCode = ioctl(msocketFd, SIOCGIFADDR, &request);
    if (0 <= returnCode) {
        inet_ntop(AF_INET, &reinterpret_cast <sockaddr_in*>(&request.ifr_addr)->sin_addr, buffer, sizeof (buffer));
        minterfaceAddress = buffer;
    } else {
        minterfaceAddress = "noInterface";
    }

    returnCode = ioctl(msocketFd, SIOCGIFHWADDR, &request);

    if (0 <= returnCode) {
        // IFHWADDRLEN
        mmacAddress.resize(12);
        const char* pData = request.ifr_hwaddr.sa_data;
        snprintf(mmacAddress.data(), mmacAddress.length() + 1, "%02x%02x%02x%02x%02x%02x", pData[0], pData[1], pData[2], pData[3], pData[4], pData[5]);
    } else {
        mmacAddress = "noInterface";
    }

}



void INetwork::active() {
    const char * args[] = {nullptr, nullptr, mname.data(), "active", nullptr};
    mprocessCreator.runScript(NETWORK_MANAGE_SCRIPT, args);

}


bool INetwork::running(short flags) {
    return IFF_RUNNING == (flags & IFF_RUNNING);
}

